/*Copyright 2012 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
#limitations under the License.*/

/* Settings & defaults

	EnemyClass

	rotAngle			undefined	faceAngleRadians
	dir					undefined	dir 			vec2 initial direction of movement
	!!dirNormalize		undefined 	dirNormalize	normalize dir vector so speed is always speed
	lifetime			0			lifetimeInSeconds
	_dmgAmt				0			damage			amount of damage dealt onTouch
	health				10 			health
	_speed				0 			speed
	_animFrameName		undefined	animFrameName	
	_impactFrameName	undefined	impactFrameName
	_impactSound		undefined	impactSound

	TurretClass
						(0,)		dir
	fireDelayInSeconds	4			
	animFrameName		turretR					(overridable by setting)
						
	FloatMineClass
	
	dir					(0,0)		dir
	_acceleration		(0,0)		acceleration
						
*/		

/* template enemy specialization

TEMPLATEClass = EnemyClass.extend({

	collidesWith : ['player', 'pprojectile', 'mapobject'],
	categories : ['enemy'],
	
	init: function (inputx, inputy, settings) 
	{
		// override the class standard values
		this.dir = new Vec2 (0,0);

		// run parent after setting the default values, to allow 'settings' to override these extension defaults 
		this.parent(inputx, inputy, settings);
		if (settings.SOMETHING) 
		{

		};
		
		
		var entityDef = {
		  id: "TEMPLATE",
		  x: this.pos.x,
		  y: this.pos.y,
		  halfHeight: 16,
		  halfWidth: 16,
		  damping: 0,
		  angle: 0,
		  categories: this.categories, 
		  collidesWith: this.collidesWith,
		  userData: {
			"id": "TEMPLATE",
			"ent": this
		  }
		};
		this.physBody = gPhysicsEngine.addBody(entityDef);
		this.physBody.SetLinearVelocity(new Vec2(this.dir.x * this._speed, this.dir.y * this._speed));
	
		if(IS_CLIENT)
		{
			this.zIndex = 20;
			this._spriteAnim = new SpriteSheetAnimClass();
			this._spriteAnim.loadSheet('sotee_sprites',"./img/sotee_sprites.png");
			var sprites = getSpriteNamesSimilarTo("mine");
			for(var i =0; i < sprites.length; i++)
				this._spriteAnim.pushFrame(sprites[i]);
		}
	},

	AI: function ()
	{
		// specific code here
		
		this.parent();
	},
	
    update: function () 
	{	
		this.parent();
	},

	draw: function (fractionOfNextPhysicsUpdate) { // Z: CLIENT code only called by CLIENT
		var gMap = gGameEngine.gMap;
		var ctx = gRenderEngine.context;
	
		
		//rotate based upon velocity
		var pPos = this.pos;
		if (this.physBody) pPos = this.physBody.GetPosition();
	
		var interpolatedPosition = {x:pPos.x, y:pPos.y};
	
		if(this.physBody) {
		  var velocity = this.physBody.GetLinearVelocity();
		  interpolatedPosition.x += (velocity.x * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
		  interpolatedPosition.y += (velocity.y * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
		}
		this._spriteAnim.draw(interpolatedPosition.x,interpolatedPosition.y,{rotRadians:this.rotAngle});	
	},
  
	onTouch: function (otherBody, point, impulse) 
	{
		this.parent(otherBody, point, impulse);
		//this.markForDeath = true;
	},

	kill: function() {
		this.parent();
	},
	
	on_stats: function(msg) {
		this.parent(msg);
		// TO DO : a different destroy effect for each class
	},
	//--------------------------------------

}); // class TEMPLATEClass

Factory.nameClassMap['TEMPLATE'] = TEMPLATEClass;

*/

	

EnemyClass = EntityClass.extend({

	dir: null,
	_dmgAmt: 0,
	health: 30,
	lifetime: 0,
	aiInterval: 10, // every ai_interval updates, the ai is run to reduce processing
	aiTick: 0,
	detectRange: 400,
	_speed: 0,
	yield: 1,
	type: Constants.TYPE.enemy,

	init: function (inputx, inputy, settings) 
	{
		
		this.parent(inputx, inputy, settings);


		// override configureable parameters : rotAngle, dir, speed, lifetime, damage, impact, 
		if(settings)
		{
			if(settings.faceAngleRadians) this.rotAngle = settings.faceAngleRadians;    
		    if(settings.dir) this.dir = new Vec2(settings.dir.x, settings.dir.y);
			if(settings.speed) this._speed = settings.speed;
			if(settings.lifetimeInSeconds) this.lifetime = settings.lifetimeInSeconds;
			if(settings.damage) this._dmgAmt = settings.damage;
			if(settings.animFrameName) this._animFrameName = settings.animFrameName;
			if(settings.impactFrameName) this._impactFrameName = settings.impactFrameName;
			if(settings.impactSound) this._impactSound = settings.impactSound;
			if(settings.health) this.health = settings.health;
		}
		
	},
	
	AI: function ()
	{
		this.aiTick = 0;
	},
	
	getNearestPlayer : function ()
	{
		// quick hack, for single player, return the gPlayer0
		return ({player: gGameEngine.gPlayer0, distance: this.distanceTo (gGameEngine.gPlayer0)});
	},
	
	update: function () 
	{
	    // lifetime management
	    this.lifetime-=0.05;
    	if (this.lifetime <= 0) {
      		Logger.log ("Entity "+this.id+"end of life");
      		this.kill();

      		return;
    	};
    	
    	this.aiTick++;
    	if (this.aiTick>this.aiInterval) this.AI();
    	
    	this.on_stats({health:this.health});     

		if(this.health<=0)
    	{
        	this.isDead = true;
        	if (this.physBody) this.physBody.SetActive(false);
        	// Z:we have parent invoke kill the body immediately - we could show a dead-state sprite until timeout instead
        	this.markForDeath=true;
    	}
    	
		this.parent();
		

	},

	spawn: function (entityName) 
	{
		/* expects:
			_spawnDir {x,y}
			_spawnOffset {x,y}
			_spawnDirVariation = 0.5
			_spawnAcceleration = {x,y}
		*/

		var gMap = gGameEngine.gMap;
		var pPos = {x:this.pos.x+this._spawnOffset.x, y:this.pos.y+this._spawnOffset.y};
		var dir = {x: this._spawnDir.x+ Math.random(2*this._spawnDirVariation)-this._spawnDirVariation,
				   y: this._spawnDir.y+ Math.random(2*this._spawnDirVariation)-this._spawnDirVariation};
		
		var ent = gGameEngine.spawnEntity(entityName, pPos.x - gMap.viewRect.x, pPos.y - gMap.viewRect.y, 
		{
			name:entityName+gGameEngine.nextSpawnId(),
			pos:pPos,
			dir:dir,
			acceleration:this._spawnAcceleration
		});

		return ent;
	},

	//--------------------------------------
	kill: function () 
	{
		if (this.loot) {
			var pPos = (this.physBody) ? this.physBody.GetPosition() : this.pos;
			var ent = gGameEngine.spawnEntity(this.loot, pPos.x, pPos.y, 
			{
				name:"Pickup_"+gGameEngine.nextSpawnId(),
				pPos:pPos,
				lootType: this.lootType
			});
		};
		//remove my physics body (IF I HAVE ONE!)
		if (this.physBody) {
		  gPhysicsEngine.removeBodyAsObj(this.physBody);
		  this.physBody = null;
	  }
	  //destroy me as an ent.
	  gGameEngine.removeEntity(this);
	},
	
  
	onTouch: function (otherFixture, point, impulse) 
	{
		if (!this.physBody) return false;
		var otherBody = otherFixture.GetBody();
		if (otherBody ==null || !otherBody.GetUserData()) return false; //invalid object??
		var physOwner = otherBody.GetUserData().ent;
		
		if (IS_SERVER && this.collision(physOwner)) 
		{
				gGameEngine.dealDmg(this,physOwner,otherFixture, parseInt(this._dmgAmt));
		}
		
		
		return true; //return false if we don't validate the collision
	},
	
	fire: function (owningPlayer) 
	{ },
	
	takeDamage: function(amount, toFixture) 
	{
	  this.health -= amount;
	},
	
	on_stats: function(msg) {
	
	  //note, we detect this before the parent function gets a chance to modify us.
	  // Z: note same client effect for any enemy at the moment..
	  
	  if (!IS_CLIENT) return; // make this client code only
	  if(this.health<=0 && !this.isDead)
	  {
		  //spawn enemy death explosion!
	
		  var efct = gGameEngine.spawnEntity("InstancedEffect", this.pos.x, this.pos.y, null);
		  efct.onInit({x:this.pos.x,y:this.pos.y},
				  {	playOnce:true, 
					  similarName: this.deathEffect || "explosionC", 
					  uriToSound:"./sound/explosionA.ogg"
				  });
	   }
	   
	},
}); // class EnemyClass



TurretClass = EnemyClass.extend({

	collidesWith : ['player', 'pprojectile', 'mapobject'],
	categories : ['enemy'],
	deathEffect : "explosionA",
	
	init: function (inputx, inputy, settings) 
	{
		this.speed = 0;
		this.dir = new Vec2(0,0);
		this._animFrameName="turretR_00";
		this.lifetime = 100;
		this.parent(inputx, inputy, settings);
		this.fireDelayInSeconds = 4 / (1 || gLevel.difficulty);
		this.firing = false;
		this.nextFireTime = gGameEngine.getTime() + this.fireDelayInSeconds;
		var entityDef = {
		  id: "turret"+this.id,
		  x: this.pos.x,
		  y: this.pos.y,
		  halfHeight: 20,
		  halfWidth: 16,
		  damping: 100,
		  angle: 0,
		  categories: this.categories, 
		  collidesWith: this.collidesWith,
		  userData: {
			"id": this.id,
			"ent": this
		  }
		};
		this.physBody = gPhysicsEngine.addBody(entityDef);
		
		this.physBody.SetLinearVelocity(new Vec2(this.dir.x * this._speed, this.dir.y * this._speed));
	
		if(IS_CLIENT)
		{
			this.zIndex = 20;
			this._spriteAnim = new SpriteSheetAnimClass();
			this._spriteAnim.loadSheet('sotee_sprites',"./img/sotee_sprites.png");
			var sprites = getSpriteNamesSimilarTo(this._animFrameName);
			for(var i =0; i < sprites.length; i++)
				this._spriteAnim.pushFrame(sprites[i]);
		}
	},

	AI: function ()
	{
		var nPlayer = this.getNearestPlayer();
		var nowTime = gGameEngine.getTime();
		if (nPlayer.distance && (nPlayer.distance < this.detectRange)) {
			if (nowTime > this.nextFireTime) this.fire(nPlayer.player);
			// TODO: set this.rotAngle to the angle between nPlayer and this position, set active animation
		} else {
			this.rotAngle = 0;
		};
		
		this.parent();
	},
	
    update: function () 
	{	
		this.parent();		
	},

  draw: function (fractionOfNextPhysicsUpdate) { // Z: CLIENT code only called by CLIENT
    var gMap = gGameEngine.gMap;
    var ctx = gRenderEngine.context;

    
    //rotate based upon velocity
    var pPos = this.pos;
    if (this.physBody) pPos = this.physBody.GetPosition();

    var interpolatedPosition = {x:pPos.x, y:pPos.y};

    if(this.physBody) {
      var velocity = this.physBody.GetLinearVelocity();
      interpolatedPosition.x += (velocity.x * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
      interpolatedPosition.y += (velocity.y * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
    }
    var dPX = gRenderEngine.getScreenPosition(interpolatedPosition).x;
    var dPY = gRenderEngine.getScreenPosition(interpolatedPosition).y;
    
	drawSprite("turretR_base.png", dPX, dPY, {ctx:ctx,noMapTrans:true});	
	// TEST IF THIS WORKS and then still this should be split in animation and aiming 
	//_spriteAnim.draw(interpolatedPosition.x,interpolatedPosition.y,{rotRadians:this.rotAngle});
	
  },
  
  fire: function (aimedPlayer) 
  {
    this.parent(aimedPlayer);
    var gMap = gGameEngine.gMap;

    // take position from physBody or entity pos if no physBody.
    var pPos = (this.physBody) ? this.physBody.GetPosition() : this.pos;

    // fire from top of turret to avoid collision
	pPos = {x:pPos.x, y:pPos.y-32};
	var aimPoint = new Vec2(aimedPlayer.pos.x, aimedPlayer.pos.y);
	var dir = new Vec2(aimPoint.x-pPos.x, aimPoint.y-pPos.y);
	dir.Normalize();
	
	var ent = gGameEngine.spawnEntity("SimpleProjectile", pPos.x - gMap.viewRect.x, pPos.y - gMap.viewRect.y, 
	{
		name:"Turret shot "+gGameEngine.nextSpawnId(),
		//owner:this,
		//faceAngleRadians:0,
		type: Constants.TYPE.ENEMYPROJECTILE,
		categories: ['eprojectile'],
		collidesWith: ['player', 'mapobject'],
		damage: 25,
		pos:pPos,
		dir:dir,
		lifetimeInSeconds:20,
		speed:150,
		animFrameName:"shotB",
		//spawnSound:"./sound/shotgun_shoot0.ogg",
		impactFrameName:"explosionC",
		//impactSound:"./sound/bounce0.ogg"
	});
	this.nextFireTime = gGameEngine.getTime() + this.fireDelayInSeconds;
  },
  
  on_stats: function(msg) {
  
  	this.parent(msg);
  	
  	// TO DO : a different destroy effect for each class
   },
  //--------------------------------------

}); // class TurretClass

Factory.nameClassMap['Turret'] = TurretClass;

FloatMineClass = EnemyClass.extend({

	collidesWith : ['player', 'pprojectile', 'mapobject'],
	categories : ['enemy'],
	deathEffect : "explosionA",
	
	init: function (inputx, inputy, settings) 
	{
		// override the class standard values
		this.health = 150;
		this._dmgAmt = 50;
		this.lifetime = 100;
		this._speed = 200;
		this.armed = true; // does it go after players or not
		this.dir = new Vec2 (0,0);
		this._acceleration = new Vec2(0,0)
		// fire parent after setting the default values, to allow 'settings' to override these extension defaults 
		this.parent(inputx, inputy, settings);
		if (settings.acceleration) 
		{
			this._acceleration.x = settings.acceleration.x;
			this._acceleration.y = settings.acceleration.y;
		};
		
		
		var entityDef = {
		  id: "floatmine",
		  x: this.pos.x,
		  y: this.pos.y,
		  halfHeight: 12,
		  halfWidth: 12,
		  damping: .1,
		  angle: 0,
		  categories: this.categories, 
		  collidesWith: this.collidesWith,
		  userData: {
			"id": "floatmine",
			"ent": this
		  }
		};
		this.physBody = gPhysicsEngine.addBody(entityDef);
		this.physBody.SetLinearVelocity(new Vec2(this.dir.x * this._speed, this.dir.y * this._speed));
	
		if(IS_CLIENT)
		{
			this.zIndex = 20;
			this._spriteAnim = new SpriteSheetAnimClass();
			this._spriteAnim.loadSheet('sotee_sprites',"./img/sotee_sprites.png");
			var sprites = getSpriteNamesSimilarTo("mine");
			for(var i =0; i < sprites.length; i++)
				this._spriteAnim.pushFrame(sprites[i]);
		}
	},

	AI: function ()
	{
		var nPlayer = this.getNearestPlayer();
		var newDir = new Vec2(0,0);
		// if in range float toward the player
		if (this.armed && nPlayer.distance && (nPlayer.distance < this.detectRange)) {
			// impulse towards nearest player in range
			this.target = nPlayer;
			newDir = new Vec2(nPlayer.player.pos.x-this.pos.x, nPlayer.player.pos.y-this.pos.y);
			newDir.Normalize();
			newDir.x = newDir.x*this.detectRange/nPlayer.distance;
			newDir.y = newDir.y*this.detectRange/nPlayer.distance;
			// accelerate slower toward player if player further away and towards a fixed direction if given
		} else {
			this.target = null;
			if (this.moveTo) { // if a moveTO position is defined, move to it if not armed
				newDir = new Vec2(this.moveTo.x-this.pos.x, this.moveTo.y-this.pos.y);
				newDir.Normalize();
			}
		};
		this.dir.x += newDir.x+this._acceleration.x;
		this.dir.y += newDir.y+this._acceleration.y;
		this.dir.Normalize();
		this.physBody.SetLinearVelocity(new Vec2(this.dir.x * this._speed, this.dir.y * this._speed));
		
		this.parent();
	},
	
    update: function () 
	{	
		this.parent();		
	},

	draw: function (fractionOfNextPhysicsUpdate) { // Z: CLIENT code only called by CLIENT
		var gMap = gGameEngine.gMap;
		var ctx = gRenderEngine.context;
	
		
		//rotate based upon velocity
		var pPos = this.pos;
		if (this.physBody) pPos = this.physBody.GetPosition();
	
		var interpolatedPosition = {x:pPos.x, y:pPos.y};
	
		if(this.physBody) {
		  var velocity = this.physBody.GetLinearVelocity();
		  interpolatedPosition.x += (velocity.x * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
		  interpolatedPosition.y += (velocity.y * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
		}
		this._spriteAnim.draw(interpolatedPosition.x,interpolatedPosition.y,{rotRadians:this.rotAngle});	
	},
  
	onTouch: function (otherFixture, point, impulse) 
	{
		this.parent(otherFixture, point, impulse);
		
		//this.markForDeath = true;
		if (IS_CLIENT) 
		{
		  if(this._impactFrameNames)
		  {
			  var pPos = this.physBody.GetPosition();
			  var efct = gGameEngine.spawnEntity("InstancedEffect", pPos.x, pPos.y, null);
			  efct.onInit({x:pPos.x,y:pPos.y},
			  {	
				  playOnce:true, 
				  similarName:"explosionA", 
				  uriToSound:this._impactSound 
			  });
		  }			
		}
	},
	
	kill: function() {
		this.parent();
	},
	
	on_stats: function(msg) {
		
		this.parent(msg);
		
		// TO DO : a different destroy effect for each class
	},
	//--------------------------------------

}); // class FLoatMineClass

Factory.nameClassMap['FloatMine'] = FloatMineClass;


FloatMineSpawnerClass = EnemyClass.extend({

	collidesWith : ['mapobject'],
	categories : ['enemy'],	
	init: function (inputx, inputy, settings) 
	{
		// override the class standard values
		this.spawns = 50;
		this._spawnInterval = 2; // spawn a mine every 2 seconds
		this._dmgAmt = 50;
		this._spawnDir = new Vec2 (0,-2); // TODO should be 0,0, but lets spawn upward for now.
		this._spawnDirVariation = 0.5; // random direction varies - + this value
		this._spawnAcceleration = {x:-0.06, y:.25}
		this._spawnOffset = {x:0, y: 0};
		
		// fire parent after setting the default values, to allow 'settings' to override these extension defaults 
		this.parent(inputx, inputy, settings);
		
		if (settings) {
			if(settings.spawnInterval) this.spawnInterval=settings._spawnInterval;
			if(settings.spawns) this.spawns=settings.spawns;
			if(settings.spawnDir) this._spawnDir = {x:settings.spawnDir.x, y:settings.spawnDir.y};
		}
		this._nextSpawnTime = gGameEngine.getTime() + this._spawnInterval;
		this.lifetime = (1+this.spawns)*this._spawnInterval; // ensure this does not get killed before all spawns are done.
	},

	AI: function ()
	{
		if(this.spawns>0 && (this._nextSpawnTime<gGameEngine.getTime())) {
			this.spawns--;
			this._nextSpawnTime = gGameEngine.getTime()+this._spawnInterval;
			this.spawn("FloatMine");
			Logger.log ("Spawner spawns floatmine; "+this.spawns+" to go."); 
		}	
		this.parent();
	},
	
    update: function () 
	{	
		this.parent();		
	},
	
	draw: function (fractionOfNextPhysicsUpdate) 
	{
		// nothing, I'm a ghost! 
	},
  
	onTouch: function (otherFixture, point, impulse) 
	{
		// nothing, I'm a ghost!
	},
  
	on_stats: function(msg) {
		this.parent(msg);	
	// TO DO : a different destroy effect for each class
	},
  //--------------------------------------

}); // class FloatMineSpawner

Factory.nameClassMap['FloatMineSpawner'] = FloatMineSpawnerClass;


SyrphidaClass = EnemyClass.extend({
// Syrphida moves in very fast, hovers, fires and retreats quickly, a repeat setting determines how often this pattern is repeated
	collidesWith : ['player', 'pprojectile', 'mapobject'],
	categories : ['enemy'],
	deathEffect : "explosionB",
	
	init: function (inputx, inputy, settings) 
	{
		// override the class standard values
		this.dir = new Vec2 (0,0);
		this._dmgAmt = 50;
		this.lifetime = 100;
		this._speed = 50;

		// number of attacks
		this._attackRepeats = 2;
		this._attacking = false;
		this.fireNow = false;
		this.bullets = 5;

		// run parent after setting the default values, to allow 'settings' to override these extension defaults 
		this.parent(inputx, inputy, settings);
		
		var entityDef = {
		  id: "Syrphida",
		  x: this.pos.x,
		  y: this.pos.y,
		  halfHeight: 12,
		  halfWidth: 20,
		  damping: 0,
		  angle: 0,
		  categories: this.categories, 
		  collidesWith: this.collidesWith,
		  userData: {
			"id": "Syrphida",
			"ent": this
		  }
		};
		this.physBody = gPhysicsEngine.addBody(entityDef);
		this.physBody.SetLinearVelocity(new Vec2(this.dir.x * this._speed, this.dir.y * this._speed));
		this.baseDir = copy(this.dir);
	
		if(IS_CLIENT)
		{
			this.zIndex = 20;
			this._spriteAnim = new SpriteSheetAnimClass();
			this._spriteAnim.loadSheet('sotee_sprites',"./img/sotee_sprites.png");
			var sprites = getSpriteNamesSimilarTo("syrphida");
			for(var i =0; i < sprites.length; i++)
				this._spriteAnim.pushFrame(sprites[i]);
		}
	},

	AI: function ()
	{
		// specific code here
		if (!this._attacking) {
			if  (this._attackRepeats>0) {
				this._attackRepeats--;
				this._attacking = true;
				this.dir = new Vec2(-1,((this._attackRepeats-.7)*-.3)*this.baseDir.y);
				this.tween({_speed : 250}, 1, {
					easing: Tween.Easing.Cubic.EaseIn,
					delay: Math.max(0,1-this._attackRepeats)
				}).start();
				this.tween({_speed : 0}, 1.5, {
					easing: Tween.Easing.Linear.EaseNone, 
					delay: 1.5, 
					onComplete: function() {
						this.obj.fire();
						this.obj.dir.x = 1;
						this.obj._speed = 300;
					}
				}).start();
				this.tween({_speed: 0}, 1, {
					easing: Tween.Easing.Cubic.EaseOut,
					delay: 4.5,
					onComplete: function() { 
							this.obj._attacking = false;
							this.obj.dir = copy (this.obj.baseDir);
							this.obj._speed = 60;
					}
				}).start();
			} else {
				this.dir = new Vec2(-1,this.baseDir.y);
				this._speed = 150;
				this._attacking = true;
			}
		};
		this.dir.Normalize();
		this.physBody.SetLinearVelocity(new Vec2(this.dir.x * this._speed, this.dir.y * this._speed));

		this.parent();
	},
	
    update: function () 
	{	
		this.parent();
	},

	draw: function (fractionOfNextPhysicsUpdate) { // Z: CLIENT code only called by CLIENT
		var gMap = gGameEngine.gMap;
		var ctx = gRenderEngine.context;
	
		
		//rotate based upon velocity
		var pPos = this.pos;
		if (this.physBody) pPos = this.physBody.GetPosition();
	
		var interpolatedPosition = {x:pPos.x, y:pPos.y};
	
		if(this.physBody) {
		  var velocity = this.physBody.GetLinearVelocity();
		  interpolatedPosition.x += (velocity.x * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
		  interpolatedPosition.y += (velocity.y * Constants.PHYSICS_LOOP_HZ) * fractionOfNextPhysicsUpdate;
		}
		this._spriteAnim.draw(interpolatedPosition.x,interpolatedPosition.y,{rotRadians:this.rotAngle});	
	},
  
	onTouch: function (otherFixture, point, impulse) 
	{
		this.parent(otherFixture, point, impulse);
		//this.markForDeath = true;
	},

	kill: function() 
	{
		this.parent();
	},

	fire: function () 
	{
		var gMap = gGameEngine.gMap;

		// take position from physBody or entity pos if no physBody.
		var pPos = (this.physBody) ? this.physBody.GetPosition() : this.pos;
		var uB = Math.floor(this.bullets / 2);
		var lB = uB - this.bullets;

		// fire from left of Syrphida to avoid collision
		pPos.x -= 20;
		pPos.y -= lB * 3;

		for (var i=lB;i<uB;i++) { //fire five bullets in arc
			var dir = new Vec2(-Math.cos(i/Math.PI/5), Math.sin(i/Math.PI/5));
			dir.Normalize();
			pPos.y += 5; // create an initial vertical spread

			var ent = gGameEngine.spawnEntity("SimpleProjectile", pPos.x - gMap.viewRect.x, pPos.y - gMap.viewRect.y, 
			{
				name:"SyrphidaShot"+gGameEngine.nextSpawnId(),
				//owner:this,
				//faceAngleRadians:0,
				type: Constants.TYPE.ENEMYPROJECTILE,
				categories: ['eprojectile'],
				collidesWith: ['player', 'mapobject'],
				damage: 25,
				pos:pPos,
				dir:dir,
				lifetimeInSeconds:20,
				speed:150,
				animFrameName:"shotB",
				//spawnSound:"./sound/shotgun_shoot0.ogg",
				impactFrameName:"explosionC",
				//impactSound:"./sound/bounce0.ogg"
			});
		};
	},
	on_stats: function(msg) {
		this.parent(msg);
		// TO DO : a different destroy effect for each class
	},
	//--------------------------------------

}); // class SyrphidaClass

Factory.nameClassMap['Syrphida'] = SyrphidaClass;

